﻿#region " LICENSE "
// DRILL - Dependency Resolution Interface Layer Library
// Copyright (c) 2008-2012 Wade A. Reynolds. All rights reserved.
// http://drill.codeplex.com/
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using Drill.Extensibility;
using Drill.TestSupport.TestDomains.SimpleDomain;

namespace Drill.TestSupport.Mocks.MockDrillBits
{
	public class SimpleDomainMockDrillBit : IDrillBit
	{
		private readonly Dictionary<Type, Func<string, object>> _getInstanceHandlerMap;
		private readonly Dictionary<Type, Func<object>> _getAllInstancesHandlerMap;

		public SimpleDomainMockDrillBit()
		{
			ResolverObject = null;

			_getInstanceHandlerMap = new Dictionary<Type, Func<string, object>>
				{
					{ typeof(ITestObjA), HandleGetInstanceITestObjA }
				  , { typeof(ITestObjB), HandleGetInstanceITestObjB }
				};

			_getAllInstancesHandlerMap = new Dictionary<Type, Func<object>>
				{
					{ typeof(ITestObjA), HandleGetAllInstancesITestObjA }
				  , { typeof(ITestObjB), HandleGetAllInstancesITestObjB }
				};
		}

		protected Dictionary<Type, Func<string, object>> GetInstanceHandlerMap { get { return _getInstanceHandlerMap; } }

		private static object HandleGetInstanceITestObjA(string name)
		{
			return new TestObjA();
		}

		private static object HandleGetInstanceITestObjB(string name)
		{
			if (name == "MyObjB")
			{
				return new TestObjB();
			}
			return new TestObjBWrapper(new TestObjB());
		}

		private static object HandleGetAllInstancesITestObjA()
		{
			return new List<ITestObjA> { new TestObjA() };
		}

		private static object HandleGetAllInstancesITestObjB()
		{
			return new List<ITestObjB> { new TestObjB(), new TestObjBWrapper(new TestObjB()) };
		}

		/// <summary>
		/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
		/// </summary>
		/// <filterpriority>2</filterpriority>
		public void Dispose()
		{
		}

		/// <summary>
		/// Gets an instance of the type specified by <paramref name="targetType"/>.
		/// </summary>
		/// <param name="targetType">The type of object to be retrieved.</param>
		/// <returns>An instance of the requested type.</returns>
		public virtual object GetInstance(Type targetType)
		{
			Func<string, object> handler;
			return _getInstanceHandlerMap.TryGetValue(targetType, out handler) ? handler(null) : null;
		}

		/// <summary>
		/// Gets a named instance of the type specified by <paramref name="targetType"/>.
		/// </summary>
		/// <param name="targetType">The type of object to be retrieved.</param>
		/// <param name="name">The name of the specific object instance.</param>
		/// <returns>An instance of the requested named type.</returns>
		public virtual object GetInstance(Type targetType, string name)
		{
			Func<string, object> handler;
			return _getInstanceHandlerMap.TryGetValue(targetType, out handler) ? handler(name) : null;
		}

		/// <summary>
		/// Get all instances of the type specified by <paramref name="targetType"/>.
		/// </summary>
		/// <param name="targetType">The type of object to be retrieved.</param>
		/// <returns>
		/// An <see cref="IEnumerable"/> instance representing all 
		/// available instances of the requested type.
		/// </returns>
		public virtual IEnumerable GetAllInstances(Type targetType)
		{
			Func<object> handler;
			return _getAllInstancesHandlerMap.TryGetValue(targetType, out handler) ? (IEnumerable)handler() : null;
		}

		/// <summary>
		/// Gets an instance of the type specified by <typeparamref name="TTargetType"/>.
		/// </summary>
		/// <typeparam name="TTargetType">The type of object to be retrieved.</typeparam>
		/// <returns>An instance of the requested type.</returns>
		public virtual TTargetType GetInstance<TTargetType>()
		{
			Func<string, object> handler;
			return _getInstanceHandlerMap.TryGetValue(typeof(TTargetType), out handler) ? (TTargetType)handler(null) : default(TTargetType);
		}

		/// <summary>
		/// Gets a named instance of the type specified by <typeparamref name="TTargetType"/>.
		/// </summary>
		/// <typeparam name="TTargetType">The type of object to be retrieved.</typeparam>
		/// <param name="name">Name the object was registered with.</param>
		/// <returns>An instance of the requested named type.</returns>
		public virtual TTargetType GetInstance<TTargetType>(string name)
		{
			Func<string, object> handler;
			return _getInstanceHandlerMap.TryGetValue(typeof(TTargetType), out handler) ? (TTargetType)handler(name) : default(TTargetType);
		}

		/// <summary>
		/// Get all instances of the type specified by <typeparamref name="TTargetType"/>.
		/// </summary>
		/// <typeparam name="TTargetType">The type of object to be retrieved.</typeparam>
		/// <returns>
		/// An <see cref="IEnumerable{TTargetType}"/> instance representing all 
		/// available instances of the requested type.
		/// </returns>
		public virtual IEnumerable<TTargetType> GetAllInstances<TTargetType>()
		{
			Func<object> handler;
			return _getAllInstancesHandlerMap.TryGetValue(typeof(TTargetType), out handler) ? (IEnumerable<TTargetType>)handler() : null;
		}

		/// <summary>
		/// Gets the object the DrillBit uses to resolve types.
		/// </summary>
		/// <value>
		/// The object the DrillBit uses to resolve types.
		/// </value>
		/// <remarks>
		/// The resolver object is usually the container object when the DrillBit wraps a DI container.
		/// It may also some other type of object such as a service locator object or any other type of object imaginable.
		/// </remarks>
		public virtual object ResolverObject { get; private set; }
	}
}